package ewu

import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.HashMap
import ewu._
import lang.LOC
import ewu.expressions.ArrayAtIndex
import ewu.expressions.ExpArray
import gui._
import scala.swing.Dialog
import scala.swing.Dialog._

/**
 * Die Klasse AbstractEnvironment stellt eine generische Umgebung
 * dar. Es sind ferner Funktionen fuer das Hinzufuegen und Abfragen
 * von Variablen in der Umgebung definiert.
 */

abstract class AbstractEnvironment[T] {
  val map: HashMap[String, T] = new HashMap[String, T]();

  def getValue(name: String): Option[T] = map.get(name)

  def isDefined(name: String): Boolean = map.contains(name)

  def addValue(name: String, value: T) : AbstractEnvironment[T] = {
    map.put(name, value)
    return this
  }
  
  def getNameAtPos(pos: Int) : String = {
    var counter = 0;
    for(i <- map) {
      if(counter == pos)
        return i._1
      counter += 1
    }
    return null
  }
  
  def size : Int = map.size
  
  def setValue(name: String, value: T) = map.update(name, value)

  def deleteValue(name: String) = map.remove(name)
  
  override def toString: String =
    "[ ---- " + LOC.get("Variablenbelegung") + " ---> ]\n" + 
    toString_Rek(map.toList.sortWith((e1 , e2) => e1._1.compareTo(e2._1) < 0)) + 
    "\n[ <--- " + LOC.get("Variablenbelegung") + " ---- ]"

  private def toString_Rek(list: List[(String, T)]): String = {
    list match {
      case ((name, value) :: xs) =>
        if (xs.length > 0) {
          if (value.equals(1234567890))
            "[ " + name + ":? ]\n " + toString_Rek(xs)
          else
            "[ " + name + ":" + value.toString + " ]\n" + toString_Rek(xs)
        }
        else {
          if (value.equals(1234567890))
            "[ " + name + ":? ]"
          else
            "[ " + name + ":" + value.toString + " ]"
        }
      case _ => ""
    }
  }
  
  private def tab (t: Int): String =
    if (t > 0) " " + tab(t-1)
    else ""
}

class ArrayEnvironment extends AbstractEnvironment[KArray]

/**
 * Die Klasse Environment stellt eine Umgebung mit dem
 * Typparameter Expression dar. Dadurch ist es moeglich,
 * ganze Expressions als Werte fuer Variablen in die 
 * Umgebung zu uebernehmen.
 */

case class Environment extends AbstractEnvironment[Expression] {
  def getValue(v: Name): Option[BigInt] = map.get(v.name) match {
    case Some(x:Number) => Some(x.value)
    case Some(x) => None
    case None => None
  }

  def getArray(v: Name): ExpArray = map.get(v.name) match {
    case Some(x:ExpArray) => x
    case Some(x) => null
    case None => null
  }
  
  def getVar(v: Name): Number = map.get(v.name) match {
    case Some(x:Number) => x
    case Some(x) => null
    case None => null
  }

  def setValue(variable: Expression, value: Expression) : Unit = {
    variable match {
      case x:ArrayAtIndex => this.getArray(Name(x.name)).setValue(x.index.evaluate(this).get.toInt, value)
      case x:Name => this.setValue(x.name, value)
      case _ => throw new IllegalArgumentException(
          "Variable no suitable Expression: " + variable.toString)
    }
  }

  def addValue(variable: Name, value: Expression) : Environment = {
    map.put(variable.name, value)
    return this
  }
  
  def addValue(variable: Name, value: BigInt) : Environment = {
    map.put(variable.name, Number(value))
    return this
  }
  
  override def addValue(variable: String, value: Expression) : Environment = {
    map.put(variable, value)
    return this
  }
  
  def addValue(variable: String, value: BigInt) : Environment = {
    map.put(variable, Number(value))
    return this
  }
  
  def addValue(variable: Name) : Environment = {
    map.put(variable.name, null)
    return this
  }
  
  def addValue(variable: String) : Environment = {
    map.put(variable, null)
    return this
  }
  
  def addValue(variables: ArrayBuffer[String], value: Expression) : Environment = {
    var it = variables.iterator
    while(it.hasNext) {
      var item = it.next()
      addValue(Name(item),value)
    }
    return this
  }
  
  def addValues(env: Environment) : Environment = {
    var it = env.map.iterator
    while(it.hasNext) {
      var item = it.next() match {
        case (x,a) => addValue(x,a)
        case _ => null
      }
    }
    return this
  }

  def deleteValue(variable: Name) = map.remove(variable.name)

  def isDefined(v: Name): Boolean = map.contains(v.name)

}